package phoenix.core;

import org.testng.TestException;

import phoenix.core.config.extensions.ConfigExt;
import phoenix.core.data_models.CountersDataModel;
import phoenix.core.data_models.TestUserDataModel;
import phoenix.core.data_models.extentions.TestDataModelExt;
import phoenix.core.helpers.HtmlHelper;
import phoenix.core.helpers.HttpUrlHelper;
import phoenix.core.helpers.PageBackendHelper;
import phoenix.core.helpers.PageMailHelper;
import phoenix.core.helpers.PageMobAndroidHelper;
import phoenix.core.helpers.PageMobSiteHelper;
import phoenix.core.helpers.PageWebHelper;
import phoenix.core.helpers.RedmineHelper;
import phoenix.core.helpers.extensions.DBHelperExt;
import phoenix.core.helpers.extensions.GmailHelperExt;
import phoenix.core.helpers.extensions.LoggerHelperExt;
import phoenix.core.helpers.extensions.MailHelperExt;
import phoenix.core.helpers.extensions.MobDriverHelperExt;
import phoenix.core.helpers.extensions.RandomizerHelperExt;
import phoenix.core.helpers.extensions.StringHelperExt;
import phoenix.core.helpers.extensions.TestHelperExt;
import phoenix.core.helpers.extensions.WebDriverHelperExt;
import core.ApplicationManager;
import core.helpers.JavaScriptHelper;

/**
 * The main class, manager of the project.
 */
public class PhoenixManager extends ApplicationManager
{
	// Application manager instance
	private static ApplicationManager manager;

	// Data Models
	private static TestDataModelExt testModel;
	private static TestUserDataModel testUserModel;
	private CountersDataModel countersData;

	// Helpers
	private PageWebHelper webPages;
	private PageMobSiteHelper mobilePages;
	private PageMobAndroidHelper androidPages;
	private PageMailHelper mailPages;
	private PageBackendHelper backendPages;
	private RedmineHelper redmine;

	// Extensions
	private ConfigExt config;
	private static DBHelperExt db;
	private static JavaScriptHelper js;
	private static RandomizerHelperExt randomizer;
	private static WebDriverHelperExt webDriver;
	private static MobDriverHelperExt mobDriver;
	private LoggerHelperExt logger;
	private TestHelperExt testHelper;
	private GmailHelperExt gmail;
	private MailHelperExt mailExt;
	private StringHelperExt stringHelperExt;
	private HtmlHelper html;
	private HttpUrlHelper httpURLConnection;

	/**
	 * Initializes PhoenixManager
	 */
	public PhoenixManager()
	{
		manager = new ApplicationManager();
	}

	/**
	 * Initializes a test
	 * @param p_project
	 * @param p_server
	 * @param p_os
	 * @param p_platform
	 * @param p_site
	 * @param p_build
	 * @param p_location
	 * @param p_proxy
	 * @param p_browserName
	 * @param p_browserVersion
	 * @param p_saucelabsUser
	 * @param p_saucelabsKey
	 * @param p_appiumPort
	 * @param p_appiumUdid
	 * @param p_appiumBootstrapPort
	 * @param p_appiumChromedriverPort
	 * @return
	 */
	public boolean initPhoenix(String p_project, String p_server, String p_os, String p_platform, String p_site, String p_build, String p_location,
			String p_proxy, String p_browserName, String p_browserVersion, String p_saucelabsUser, String p_saucelabsKey, String p_appiumPort,
			String p_appiumUdid,
			String p_appiumBootstrapPort, String p_appiumChromedriverPort)
	{

		wd().driver = null;
		// Check connection to DB
		if (db().isConnected())
		{
			// Launch the browser
			return init(p_project, p_server, p_os, p_platform, p_site, p_build, p_location, p_proxy, p_browserName, p_browserVersion,
					p_saucelabsUser, p_saucelabsKey, p_appiumPort, p_appiumUdid,
					p_appiumBootstrapPort, p_appiumChromedriverPort);
		}

		return false;
	}

	/**
	 * Initializes the test
	 * @param p_project
	 * @param p_server
	 * @param p_os
	 * @param p_platform
	 * @param p_site
	 * @param p_build
	 * @param p_location
	 * @param p_proxy
	 * @param p_browserName
	 * @param p_browserVersion
	 * @param p_saucelabsUser
	 * @param p_saucelabsKey
	 * @param p_appiumPort
	 * @param p_appiumUdid
	 * @param p_appiumBootstrapPort
	 * @param p_appiumChromedriverPort
	 * @return
	 */
	public boolean init(String p_project, String p_server, String p_os, String p_platform, String p_site, String p_build, String p_location, String p_proxy,
			String p_browserName, String p_browserVersion, String p_saucelabsUser, String p_saucelabsKey, String p_appiumPort, String p_appiumUdid,
			String p_appiumBootstrapPort, String p_appiumChromedriverPort)
	{
		this.testModel()
				.setProjectName(p_project)
				.setServerType(p_server)
				.setOS(p_os)
				.setPlatform(p_platform)
				.setSiteName(p_site)
				.setBuild(p_build)
				.setLocation(p_location)
				.setProxy(getProxy(p_proxy))
				.setBrowserName(p_browserName)
				.setBrowserVersion(p_browserVersion)
				.setSaucelabsUsername(p_saucelabsUser)
				.setSaucelabsKey(p_saucelabsKey)
				.setAppiumPort(p_appiumPort)
				.setAppiumBootstrapPort(p_appiumBootstrapPort)
				.setAppiumChromedriverPort(p_appiumChromedriverPort)
				.setAppiumUdid(p_appiumUdid);
		this.testModel().setSiteURL();

		testModel().print();

		if (testModel().getPlatform().equals(config().PLATFORM_WEB))
		{
			Integer at = 0;
			while (wd().runLocalBrowser(testModel().getBrowserName(), testModel().getProxy()) == null)
			{
				manager.log().info("We are waiting for another try");
				wd().wait(120);

				if (at == 5)
				{
					log().error("Unable to start browser after five attempts");
					throw new TestException("after 5 attempts");
				}
				at++;
			}
		}
		else if (testModel().getPlatform().equals(config().PLATFORM_MOBILE) || testModel().getPlatform().equals(config().PLATFORM_APP))
		{
			md().runLocalBrowser();
		}

		return false;
	}

	/**
	 * Provides access to project configuration
	 * @return ConfigExt instance
	 */
	@SuppressWarnings("static-access")
	@Override
	public ConfigExt config()
	{
		if (this.config == null)
		{
			config = new ConfigExt(this);
			super.config = this.config;
		}

		return this.config;
	}

	/**
	 * Provides methods for randomizing data
	 * @return RandomizerHelper instance
	 */
	public HttpUrlHelper httpURLConnection()
	{
		if (httpURLConnection == null)
		{
			httpURLConnection = new HttpUrlHelper(this);
		}

		return httpURLConnection;
	}

	/**
	 * Provides access to base methods on all web pages
	 * @return PageWebHelper instance
	 */
	public PageWebHelper web()
	{
		if (webPages == null)
		{
			webPages = new PageWebHelper(this);
		}

		return webPages;
	}

	/**
	 * Provides access to base methods on all mail pages
	 * @return PageMailHelper instance
	 */
	public PageMailHelper mails()
	{
		if (mailPages == null)
		{
			mailPages = new PageMailHelper(this);
		}

		return mailPages;
	}

	/**
	 * Provides access to base methods on all mobile pages
	 * @return PageMobileHelper instance
	 */
	public PageMobSiteHelper mob()
	{
		if (mobilePages == null)
		{
			mobilePages = new PageMobSiteHelper(this);
		}

		return mobilePages;
	}

	/**
	 * Provides access to base methods on all android pages
	 * @return PageMobAndroidHelper instance
	 */
	public PageMobAndroidHelper android()
	{
		if (androidPages == null)
		{
			androidPages = new PageMobAndroidHelper(this);
		}

		return androidPages;
	}

	/**
	 * Provides access to base methods on all mobile pages
	 * @return PageMobileHelper instance
	 */
	public PageBackendHelper backend()
	{
		if (backendPages == null)
		{
			backendPages = new PageBackendHelper(this);
		}

		return backendPages;
	}

	/**
	 * Provides access to extension methods for working with DB
	 * @return DBHelperExt instance
	 */
	@Override
	public DBHelperExt db()
	{
		if (db == null)
		{
			db = new DBHelperExt(manager, this);
		}
		return db;
	}

	/**
	 * Provides access to extension methods for working with DB
	 * @return DBHelperExt instance
	 */
	@Override
	public JavaScriptHelper js()
	{
		if (js == null)
		{
			js = new JavaScriptHelper(this);
		}
		return js;
	}

	/**
	 * Provides access to extension methods for working with DB
	 * @return GmailHelperExt instance
	 */
	@Override
	public GmailHelperExt mail()
	{
		if (gmail == null)
		{
			gmail = new GmailHelperExt(manager, this);
		}
		return gmail;
	}

	/**
	 * Provides access to extension methods for working random data
	 * @return RandomizerHelperExt instance
	 */
	@Override
	public RandomizerHelperExt randomizer()
	{
		if (randomizer == null)
		{
			randomizer = new RandomizerHelperExt(manager, this);
		}
		return randomizer;
	}

	/**
	 * Web driver helper
	 * @return WebDriverHelperExt instance
	 */
	@Override
	@SuppressWarnings("static-access")
	public WebDriverHelperExt wd()
	{
		if (webDriver == null)
		{
			webDriver = new WebDriverHelperExt(manager, this);
			super.webDriver = webDriver;
		}

		return webDriver;
	}

	/**
	 * Web driver helper
	 * @return WebDriverHelperMobExt instance
	 */
	@SuppressWarnings("static-access")
	@Override
	public MobDriverHelperExt md()
	{
		if (mobDriver == null)
		{
			mobDriver = new MobDriverHelperExt(manager, this);
			super.mobDriver = mobDriver;
		}

		return mobDriver;
	}

	/**
	 * LoggerHelperExt
	 * @return LoggerHelperExt instance
	 */
	@SuppressWarnings("static-access")
	@Override
	public LoggerHelperExt log()
	{
		if (this.logger == null)
		{
			this.logger = new LoggerHelperExt(manager, this);
			super.logger = this.logger;
		}

		return this.logger;
	}

	/**
	 * Gets a current test user model
	 * @return Reference to TestUserModel
	 */
	public TestUserDataModel testUser()
	{
		if (testUserModel == null)
		{
			testUserModel = new TestUserDataModel(this);
		}

		return testUserModel;
	}

	/**
	 * Set new user model for current user
	 */
	public void setTestUser(String p_userID)
	{
		if (p_userID == null)
		{
			log().error("p_userID is empty");
		}

		testUserModel = new TestUserDataModel(this);
		testUserModel = db().getUser(p_userID);
	}

	/**
	 * Set new user model for specified user
	 */
	public TestUserDataModel fillUser(String p_userID)
	{
		if (p_userID == null)
		{
			log().error("p_userID is empty");
		}

		return db().getUser(p_userID);
	}

	/**
	 * Set new user model for current user
	 */
	public void setTestUser()
	{
		testUserModel = new TestUserDataModel(this);
	}

	/**
	 * Set user model
	 * @param p_userObject
	 */
	public void setTestUser(TestUserDataModel p_userObject)
	{
		testUserModel = p_userObject;
	}

	/**
	 * Set new user model for current user
	 * @param p_user
	 */
	public void updateTestUser(TestUserDataModel p_user)
	{
		testUserModel.setBirthDate(p_user.getBirthDate())
				.setConfirmDate(p_user.getConfirmDate())
				.setCountry(p_user.getCountry())
				.setEmail(p_user.getEmail())
				.setGender(p_user.getGender())
				.setId(p_user.getId())
				.setMembershipStatus(p_user.getMembershipStatus())
				.setPassword(p_user.getPassword())
				.setScreenname(p_user.getScreenname())
				.setSexuality(p_user.getSexuality())
				.setSiteName(p_user.getSiteName())
				.setUserKey(p_user.getUserKey())
				.setRegSource(p_user.getRegSource())
				.setRegDate(p_user.getRegDate())
				.setPlatform(p_user.getPlatform())
				.setAge(p_user.getAge())
				.setSiteId(p_user.getSiteId());
	}

	public StringHelperExt stringHelperExt()
	{
		if (stringHelperExt == null)
		{
			stringHelperExt = new StringHelperExt(this);
		}

		return stringHelperExt;
	}

	/**
	 * Sets country cookie
	 * @param p_country
	 */
	public void setCountryCookie(String p_country)
	{
		if (p_country.isEmpty())
		{
			throw new TestException("p_country is empty");
		}

		String countryIP = null;

		switch (p_country)
		{
			case ConfigExt.LOCATION_AUS:
			{
				countryIP = ConfigExt.LOCATION_AUS_IP;
				break;
			}
			case ConfigExt.LOCATION_GBR:
			{
				countryIP = ConfigExt.LOCATION_GBR_IP;
				break;
			}
			case ConfigExt.LOCATION_USA:
			{
				countryIP = ConfigExt.LOCATION_USA_IP;
				break;
			}
			case ConfigExt.LOCATION_FRA:
			{
				countryIP = ConfigExt.LOCATION_FRA_IP;
				break;
			}
			case ConfigExt.LOCATION_ITA:
			{
				countryIP = ConfigExt.LOCATION_ITA_IP;
				break;
			}
			case ConfigExt.LOCATION_ESP:
			{
				countryIP = ConfigExt.LOCATION_ESP_IP;
				break;
			}
			case ConfigExt.LOCATION_ZAF:
			{
				countryIP = ConfigExt.LOCATION_ZAF_IP;
				break;
			}
			case ConfigExt.LOCATION_NOR:
			{
				countryIP = ConfigExt.LOCATION_NOR_IP;
				break;
			}
			case ConfigExt.LOCATION_SWE:
			{
				countryIP = ConfigExt.LOCATION_SWE_IP;
				break;
			}
			case ConfigExt.LOCATION_DEU:
			{
				countryIP = ConfigExt.LOCATION_DEU_IP;
				break;
			}
			default:
			{
				countryIP = ConfigExt.LOCATION_DEF_IP;
			}
		}

		if (countryIP.isEmpty())
		{
			throw new TestException("countryIP is empty");
		}

		try
		{
			wd().deleteAllCookies();

			log().info("Set country IP: " + testModel().getLocation() + " => " + countryIP);

			if (manager.testModel().getBuild().equals(manager.config().BUILD_LIVE))
			{
				if (wd().getCurrentUrl().contains("platformphoenix") || !wd().getCurrentUrl().contains(testModel().getSiteName()))
				{
					wd().openURL("www." + testModel().getSiteName() + ".com/?ip_address=" + countryIP);
					wd().refreshPage();
				}
			}
			else if (manager.testModel().getBuild().contains(manager.config().BUILD_REL))
			{
				wd().openURL("www." + testModel().getSiteName() + "." + testModel().getBuild() + ".platformphoenix.com/?ip_address=" + countryIP);
				wd().refreshPage();
			}

		}
		catch (Exception p_ex)
		{
			log().warn("setCountryCookie : " + p_ex.toString());
		}

		String cookieURL = manager.testModel().getSiteURL();
		String cookieFinal = cookieURL.substring(cookieURL.indexOf("//") + 2, cookieURL.length());

		wd().setCookie("ip_address", countryIP, cookieFinal, "/",
				cronos().convertStringToDate("2020-01-18 00:00:00.0", "yyyy-MM-dd HH:mm:ss.S"));
		wd().refreshPage();

	}

	/**
	 * @return CountersDataModel
	 */
	public CountersDataModel getCountersData()
	{
		return countersData;
	}

	/**
	 * Set counter data
	 * @param countersData
	 */
	public void setCountersData(CountersDataModel countersData)
	{
		this.countersData = countersData;
	}

	/**
	 * Is site name ClickandFlirt
	 * @return True or false
	 */
	public boolean isCNF()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_CLICKANDFLIRT));
	}

	/**
	 * Is site name CheekyLovers
	 * @return True or false
	 */
	public boolean isCL()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_CHEECKYLOVERS));
	}

	/**
	 * Is site name EbonyFlirt
	 * @return True or false
	 */
	public boolean isEF()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_EBONYFLIRT));
	}

	/**
	 * Is site name LocalsGoWild
	 * @return True or false
	 */
	public boolean isLGW()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_LOCALSGOWILD));
	}

	/**
	 * Is site name WildBuddies
	 * @return True or false
	 */
	public boolean isWB()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_WILDBUDDIES));
	}

	/**
	 * Is site name BeNaughty
	 * @return True or false
	 */
	public boolean isBN()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_BENAUGHTY));
	}

	/**
	 * Is site name Flirt
	 * @return True or false
	 */
	public boolean isFlirt()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_FLIRT));
	}

	/**
	 * Is site name ForeignGirlfriendc
	 * @return
	 */
	public boolean isFGF()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_FOREIGNGIRLFRIEND));
	}

	/**
	 * Is site name NaughtyFever
	 * @return True or false
	 */
	public boolean isNF()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_NAUGHTYFEVER));
	}

	/**
	 * Is site name NaughtyDate
	 * @return True or false
	 */
	public boolean isND()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_NAUGHTYDATE));
	}

	public boolean isMD()
	{
		return (testModel().getSiteName().equals(ConfigExt.SITE_ID_MATUREDATING));
	}

	/**
	 * Provides methods for work with RedMine
	 * @return RedmineHelper instance
	 */
	public RedmineHelper redmine()
	{
		if (redmine == null)
		{
			redmine = new RedmineHelper(this);
		}

		return redmine;
	}

	/**
	 * Gets access to test data model
	 * @return TestDataModelExt instance
	 */
	@SuppressWarnings("static-access")
	@Override
	public TestDataModelExt testModel()
	{
		if (this.testModel == null)
		{
			this.testModel = new TestDataModelExt(this, this);
			super.testModel = this.testModel;
		}

		return this.testModel;
	}

	/**
	 * Provides the methods for values testing
	 * @return TestHelperExt instance
	 */
	@Override
	public TestHelperExt test()
	{
		if (testHelper == null)
		{
			testHelper = new TestHelperExt(manager, this);
		}

		return testHelper;
	}

	public MailHelperExt mailExt()
	{
		if (mailExt == null)
		{
			mailExt = new MailHelperExt(manager, this);
		}

		return mailExt;
	}

	public HtmlHelper html()
	{
		if (html == null)
		{
			html = new HtmlHelper(this);
		}

		return html;
	}

	/**
	 * Get a proxy by location
	 * @param p_location
	 * @return
	 */
	public String getProxy(String p_location)
	{
		String proxy = "def";

		switch (p_location)
		{
			case ConfigExt.LOCATION_GBR:
			{
				proxy = config().PROXY_GBR;
				break;
			}
			case ConfigExt.LOCATION_USA:
			{
				proxy = config().PROXY_USA;
				break;
			}
			case ConfigExt.LOCATION_AUS:
			{
				proxy = config().PROXY_AUS;
				break;
			}
			case ConfigExt.LOCATION_BRA:
			{
				proxy = config().PROXY_BRA;
				break;
			}
			case ConfigExt.LOCATION_CAN:
			{
				proxy = config().PROXY_CAN;
				break;
			}
			case ConfigExt.LOCATION_MEX:
			{
				proxy = config().PROXY_MEX;
				break;
			}
			case ConfigExt.LOCATION_FIN:
			{
				proxy = config().PROXY_FIN;
				break;
			}
			case ConfigExt.LOCATION_IND:
			{
				proxy = config().PROXY_IND;
				break;
			}
			case ConfigExt.LOCATION_IRL:
			{
				proxy = config().PROXY_IRL;
				break;
			}
			case ConfigExt.LOCATION_NZL:
			{
				proxy = config().PROXY_NZL;
				break;
			}
			case ConfigExt.LOCATION_SWE:
			{
				proxy = config().PROXY_SWE;
				break;
			}
			case ConfigExt.LOCATION_NOR:
			{
				proxy = config().PROXY_NOR;
				break;
			}
			case ConfigExt.LOCATION_ITA:
			{
				proxy = config().PROXY_ITA;
			}
			case ConfigExt.LOCATION_ESP:
			{
				proxy = config().PROXY_ESP;
				break;
			}
			case ConfigExt.LOCATION_FRA:
			{
				proxy = config().PROXY_FRA;
				break;
			}
			default:
			{
				log().info("Proxy: def");
				break;
			}
		}

		log().info("Set proxy: " + proxy);

		return proxy;
	}

	@Override
	public void shutDown()
	{
		testModel = null;
		testUserModel = null;
		countersData = null;

		// Helpers
		webPages = null;
		mobilePages = null;
		mailPages = null;
		backendPages = null;
		redmine = null;

		// Extentions
		config = null;
		db = null;
		randomizer = null;
		webDriver = null;
		logger = null;
		testHelper = null;
		gmail = null;
		mailExt = null;
		html = null;

		super.shutDown();
		manager = null;
	}
}